home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Suntar 1.3.2 / tar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-31  |  51.3 KB  |  1,753 lines  |  [TEXT/KAHL]

  1. /* Copyright 1988, Gail Zacharias.  All rights reserved.
  2.  * Permission is hereby granted to copy, reproduce, redistribute or
  3.  * otherwise use this software provided there is no monetary profit
  4.  * gained specifically from its use or reproduction, it is not sold
  5.  * rented, traded or otherwise marketed, and this copyright notice 
  6.  * and the software version number is included prominently in any copy
  7.  * made.
  8.  * This was mtar version 1.0.
  9.  *
  10.  */
  11.  
  12. /* the original mtar program was then altered to become part of suntar: 
  13. */
  14.  
  15. /*******************************************************************************\
  16.  
  17. tar writing module
  18.  
  19. part of suntar, ©1991-92 Sauro & Gabriele Speranza
  20.  
  21. This program is public domain, feel free to use it or part of it for anything
  22.  
  23. \*******************************************************************************/
  24.  
  25.  
  26. /*
  27. comments in the text explain which routines were added for suntar by us and
  28. which ones are from mtar, but most of the latter were modified more or less 
  29. heavily by us. In fact, the file is divided into three sections:
  30. a few declarations by Gail Zacharias
  31. a series of routines 100% by Speranza
  32. a series of old routines by Zacharias: only a few of them are still in the
  33.     original form, but the calling interface is usually unchanged
  34. */
  35.  
  36. #include "system7.h"
  37. #include "PB_sync.h"
  38. #include "antiglue.h"
  39.  
  40. #include <string.h>
  41. /*#include <FileMgr.h>
  42. #include <OSUtil.h>
  43. #include <HFS.h>*/
  44.  
  45. #include "suntar.h"
  46.  
  47. #include "windows.h"
  48.  
  49.  
  50. void fillmem(dest, ch, len)
  51. register char*dest;
  52. register char ch;
  53. register short len;
  54. {
  55.     while (--len>=0) *dest++ = ch;
  56. }
  57.  
  58.  
  59. #define tarsz(n)    (((n)+511L) & -512L)
  60. #define macbinsz(n)    (((n)+127L) & -128L)
  61.  
  62. static HFileInfo statb;
  63.  
  64. static Boolean binary = false, 
  65.     dataonly = false;
  66.  
  67. #define    dirmode 0777
  68. #define    filemode 0666
  69.  
  70. char *uname,
  71.      *gname;
  72.  
  73. /* Unfortunately, the Mac keeps only local time, so this will be off by
  74.    the time zone... */
  75. #define UNIXTIME    2082844800L  /* Jan 1, 1970 00:00:00 */
  76.  
  77. /*
  78. main (argc, argv)
  79.   char **argv;
  80. {
  81.   fprintf(stderr, 
  82. "This is freeware.  If you paid money for this program, you got ripped off.\n");
  83. }
  84. */
  85. /*********************** start of routines by Speranza **************************/
  86.  
  87. /* dovrò riorganizzare un po' le cose: ha senso che, come in untar, ci siano due
  88. modi di chiamare le routine di output: uno per quelli che sanno che esistono i settori
  89. (scrittura header) e uno per quelli che preferiscono vedere un flusso continuo di bytes:
  90. ovviamente ci vuole una routine per riallinearsi al settore dopo una serie di
  91. chiamate del secondo gruppo, ma questa esiste già, svuota_buffer
  92. -- Beware: the disk handling routines are organized with an external interface
  93. which looks like a continuous stream of bytes (they trasparently handle volume
  94. headers and disk swapping) but in several places the caller must know about
  95. the internal behaviour, about sector and disk numbers (e.g., it must know in
  96. which sector of which disk a file header was written) and it does so by reading
  97. the internal variables and knowing whether they are incremented before or after.
  98.  That makes things a little tricky, often less comprehensible than the untar
  99. module where the low level routines are less clever
  100. */
  101.  
  102.  
  103. #define dp printf
  104.  
  105. #define ALIAS_BIT 0x8000
  106.  
  107.  
  108. static sector_t last_header,        /* il settore contenente l'ultimo header di file
  109.                         -- the sector containing the last file header */
  110.     last_sector;    /* il settore vuoto che sarà scritto alla prossima occasione;
  111.                     nota che in questo modulo è gestito in modo un po' "sotterraneo":
  112.                     eccetto che per cose strane (header speciali, che non riguardano
  113.                     le normali routines) scrivi_settori viene sempre chiamata col
  114.                     tramite di write_next_sector (che si occupa di gestire un eventuale
  115.                     cambio disco: bisogna chiedergli comunque un settore a partire da 0,
  116.                     sa lei che a causa degli header di disco poi non è detto si vada
  117.                     al 0, ed è impossibile per bar), ma last_sector va incrementata
  118.                     subito dopo tale chiamata, col che appunto è sempre il prossimo
  119.                     settore. Attenzione che write_block butta fuori quando ha il buffer
  120.                     pieno (cioè non lo lascia con 512 bytes, lo svuota subito) 
  121.                     -- next sector to be written: after a call to write_next_sector
  122.                     which fills a sector, it was already incremented so it points
  123.                     to the next sector (or beyond the end of disk)
  124.                     */
  125. static short more_space;    /* number of free bytes in buffer, that is 512 - number of 
  126.                     bytes currently in the buffer */
  127. static short path_len=0;    /* nell'archivio scrivo solo l'ultima parte del pathname
  128.                         completo che invece uso per aprire i files
  129.                         -- The full path name is used to open files, but the stored name 
  130.                         in the archive is only the last part of it, the partial path
  131.                         from the folder which was selected by the user.
  132.                         */
  133. short inputFile;
  134. /*static IOParam pb;*/
  135. extern ParamBlockRec pb;
  136.                     /* è diventata una variabile globale per poter chiudere il file in
  137.                     caso di errore; per la verità non è necessario, basta un singolo
  138.                     campo, il RefNum... */
  139. short inf_refn;        /* refnum for an input file, used for write tar/bar and overwrite sectors */
  140. Boolean inf_is_open=false;
  141. static Boolean write_in_corso=0;    /* remembers that I was writing, hence what is in
  142.                 the disk is not correctly terminated by a null header */
  143. static Boolean devo_chiudere_in=false;
  144.  
  145. static Boolean questo_e_un_header;        /* set just before writing an header sector */
  146. unsigned char previousFormat;    /* solo per tar, quelli bar sono sempre multivolume
  147.             -- for tar format only, bar archives are always allowed to become multivolume */
  148. extern short floppy_n;
  149. extern unsigned char mac_file_name[];
  150. extern short openfile_vrefnum;
  151. extern long openfile_dirID;
  152.  
  153. static char alias_prefix[100];    /* new for suntar 1.3.2: if a/b/c happens
  154.         to be the alias of d, then the file is opened as d but must be a/b/d
  155.         in the tar archive. and if d is a directory and d/e is alias of f,
  156.         it's opened as f but will be a/b/d/f... */
  157. static char bar_date[12];
  158. static char volLabel[100];
  159. static short label_n;    /* used with volLabel for GNU archives */
  160. long my_uid,my_gid;
  161.  
  162. static char *miei_titoli[]={"\pEspelli","\pOk","\pInizializza 720k"};
  163. char FERRORita[]="Errore di lettura %d\n",
  164.     FERRORing[]="Error %d during read\n";
  165.  
  166. void chiedi_altro_disco(void);
  167. void set_bar_date(void);
  168. Boolean surely_not_mac(char*);
  169. void alias_error(short);
  170. void write_GNU_V_header(void);
  171. void fill_uname(tarh_type *);
  172.  
  173. #define FLUSH_MIN_SIZE 10240
  174.  
  175. static void chiedi_altro_disco()    /* ask for another disk */
  176. {
  177. short i;
  178. extern Boolean sm_checkbox_status,ins_checkbox_status;
  179.  
  180. ins_checkbox_status=false;
  181. diskEject();
  182.  
  183. for(;;){
  184.     sm_checkbox_status=ins_checkbox_status;
  185.     i=aspetta_inserzione(in_Italia?"\pInserisci un altro disco su cui scrivere":
  186.     "\pInsert another disk to be written",true);
  187.     ins_checkbox_status=sm_checkbox_status;
  188.     if(i!=0) raise_error();        /* un annulla... 
  189.                     -- the user clicked the Cancel button
  190.                     */
  191.     if(is_wrprot() && (di.is_not_initialized||!ins_checkbox_status)){
  192.         printf_protetto();
  193.         }
  194.     else if(di.is_not_initialized)
  195.         disk_format(false);
  196.     else{
  197.         if(ins_checkbox_status){
  198.             esamina_disco();
  199.             if(is_wrprot())
  200.                 printf_protetto();
  201.             else{
  202.                 i=warning_400_800();
  203.                 if(i==0){
  204.                     /*
  205.                     ParamText(in_Italia?"\pLa scrittura distruggerà il contenuto attuale del disco":
  206.                         "\pWriting will destroy anything is currently on this disk",PNS,PNS,PNS);
  207.                     if(my_modal_dialog(133,miei_titoli,2) == 2)
  208.                     */
  209.                     if(my_semimodal_dialog(146,miei_titoli,2,in_Italia?
  210.                         "\pLa scrittura distruggerà il contenuto attuale del disco":
  211.                         "\pWriting will destroy anything is currently on this disk",
  212.                         PNS,PNS) == 2)
  213.                         return;
  214.                     diskEject();
  215.                     }
  216.                 else if(i==2)
  217.                     return;
  218.                 }
  219.             }
  220.         else{
  221.             if(warning_400_800()!=1) return;
  222.             }
  223.         }
  224.     }
  225. }
  226.  
  227.  
  228. void reset_sector_count()
  229. {
  230. /* viene chiamata quando si dà un comando di create o append, quindi è il posto
  231. buono per inserire qualunque inizializzazione
  232. -- called for the Create and Append commands, it's the right place for initializing
  233. some variables
  234. */
  235. last_header=last_sector=0;
  236. previousFormat= tar_unknown;
  237. floppy_n=0;
  238. volLabel[0]=0;
  239. set_bar_date();        /* deve essere comune per tutto l'archivio
  240.                     -- the same value must be used for all volumes in the archive */
  241. }
  242.  
  243. void write_next_sector(void);
  244. static void write_next_sector()
  245. {
  246.  
  247.     if(last_sector>=sectors_on_floppy){
  248.         if(!bar_archive && previousFormat<=tar_singlevol&&tar_version<=tar_singlevol){
  249.             start_of_line();
  250.             printf("Disk full, write aborted !\n");        /* non dovrebbe capitare mai, */
  251.             tronca_archivio();        /* visto che controllo prima, ma nel caso...
  252.                         -- that should never happen, that's checked at every header,
  253.                         but if that check should contain a bug, don't crash
  254.                         */
  255.             raise_error();
  256.             }
  257.         last_sector=0;    /* deve essere =0 perché scrivo sempre tutti 
  258.                 i settori (non per niente questa routine si chiama così...) */
  259.         chiedi_altro_disco();
  260.         }
  261.     if(last_sector==0){
  262.         floppy_n++;
  263.         warning_first_write(0);
  264.         if(bar_archive){
  265.             write_bar_volume_header();
  266.             }
  267.         else{
  268.             if(volLabel[0] && tar_version==tar_GNU) write_GNU_V_header();
  269.             if(floppy_n!=1 && !questo_e_un_header &&
  270.                (previousFormat==tar_GNU || tar_version==tar_GNU&&previousFormat!=tar_AIX) ){
  271.                        /* scrivi un header di continuazione file 
  272.                     -- write a 'M' header for a file splitted between disks */
  273.                 write_tar_volume_header();
  274.                 }
  275.             }
  276.         }
  277.     scrivi_settore(last_sector,disk_buffer);
  278.     check_wr_err();
  279.     questo_e_un_header=false;
  280.     settori_passati++;
  281. }
  282.  
  283.  
  284. void dim_720k_button(WindowRecord *);
  285. static void dim_720k_button(w)
  286. WindowRecord *w;
  287. /* dim the button which can't be used without a SuperDrive */
  288. {
  289.     short    kind;
  290.     Handle    h;
  291.     Rect    r;
  292.     GetDItem ((DialogPtr)w,3,&kind,&h,&r);
  293.     HiliteControl(h, 255);
  294. }
  295.  
  296. short warning_400_800()
  297. {
  298. /* returns:
  299. 0 no dialog
  300. 1 dialog and the disk was ejected
  301. 2 dialog and the disk is OK
  302. */
  303. extern short drive_type[max_drive];
  304. #define SUPERDRIVE    4
  305. register short i=0;
  306. if( (sectors_on_floppy==800 || sectors_on_floppy==1600) && !accetta_GCR){
  307.     unsigned char b[2];
  308.     b[0]=1;
  309.     b[1]= sectors_on_floppy==800 ? '4' : '8';
  310.     #if 0    /* version 1.3.1 */
  311.     if(in_Italia )
  312.         ParamText("\pUn disco da ",b,"\p00K non può essere\rletto su un sistema UNIX",PNS);
  313.     else
  314.         ParamText("\pA ",b,"\p00K disk can\'t be read\ron an UNIX machine",PNS);
  315.     my_alert();
  316.     #else
  317.     {static Point wPos={-1,-1};
  318.     i=drive_type[drive_number-1]&0x0F;
  319.  
  320.     i=semimodalDialog(145,&wPos,NULL,miei_titoli,3,
  321.         in_Italia?"\pUn disco da ":"\pA ",b,
  322.         in_Italia?"\p00K non può essere\rletto su un sistema UNIX":
  323.         "\p00K disk can\'t be read\ron an UNIX machine",
  324.         teJustCenter,true, di.supports_720K ? NULL : dim_720k_button);
  325.     }
  326.     #endif
  327.  
  328.     if(i==1)    /* Eject */
  329.         diskEject();
  330.     else if(i==3){    /* initialize 720k */
  331.         short inPlace;
  332.         
  333.         disk_format(false);
  334.         if( sectors_on_floppy!=1440 ||        /* disk_format may fail, or may be
  335.                     canceled by the user: it would be better to have a return code
  336.                     from it, but I can succeed to understand what happened without
  337.                     any return code */
  338.            !drive_number || testa_stato(&inPlace,1) || !inPlace){
  339.             diskEject();
  340.             return 1;
  341.             }
  342.         else
  343.             return 2;
  344.         }
  345.     }
  346. return i;
  347. }
  348.  
  349.  
  350. void printf_protetto()
  351. {
  352.     start_of_line();
  353.     printf(in_Italia?"Disco protetto da scrittura !\n":"Write protected disk !\n");
  354.     diskEject();
  355. }
  356.  
  357. static Boolean surely_not_mac(buffer)
  358. char buffer[512];
  359. {
  360. if(di.disk_code!=noErr) return true;
  361. leggi_settore(2,buffer);
  362. return err_code!=0;
  363. }
  364.  
  365. short warning_first_write(n)
  366. short n;
  367. /* n=0 if called by a command in the write menu (don't return without a writable disk),
  368. 1 for initialize */
  369. {
  370. /* called before the first write to a disk which is still containing
  371. what it was containing when it was inserted: it's the last chance to
  372. avoid a data loss
  373. returns:
  374. -1: (only if n=1) the user canceled the operation but the disk wasn't ejected yet
  375. 0:    the user approved the operation
  376. 1:    it's not a Mac disk (no dialog)
  377. 2:    it's an empty Mac disk (no dialog)
  378. */
  379.  
  380. char buffer[512];
  381.  
  382. for(;;){
  383.     Boolean guarda_files;
  384.  
  385.     while(surely_not_mac(buffer)){
  386.         short inPlace;
  387.         testa_stato(&inPlace,0);
  388.         if(!n&&di.is_not_initialized){
  389.             disk_format(false);
  390.             if(drive_number){
  391.                 if(testa_stato(&inPlace,1) || !inPlace)
  392.                     diskEject();
  393.                 else if(is_wrprot())
  394.                     printf_protetto();
  395.                 else
  396.                     return 1;
  397.                 }
  398.             chiedi_altro_disco();
  399.             }
  400.         else
  401.             return 1;
  402.         }
  403. /*printf("n files=%d\n",*(int*)&buffer[12]);
  404. printf("n dirs=%d\n",*(int*)&buffer[82]);
  405. printf("n files tot=%ld\n",*(long*)&buffer[84]);
  406. printf("n dirs tot=%ld\n",*(long*)&buffer[88]);
  407. */
  408. /* if it's a Macintosh disk (same test used by is_mac_disk in suntar.c) see if
  409. it contains more than one file (the first one is the desktop) or more than zero folders
  410. */
  411.  
  412.     if( (*(short*) buffer== 0xD2D7 || *(short*) buffer== 0x4244) ){ /* MFS o HFS */
  413.         guarda_files=true;
  414.         if( *(short*) buffer== 0x4244 && ((*(short*)&buffer[10])&0x200)){
  415.             /* see TN 287: System 7 sets that flag if one or more bad sectors were 
  416.             found and marked as unusable */
  417.             ParamText(in_Italia?"\pQuesto disco contiene dei settori marcati difettosi":
  418.             "\pIn this disk some sectors are marked bad",PNS,PNS,PNS);
  419.             if( my_modal_dialog(133,miei_titoli,2) ==1){
  420.                 if(n) return -1;
  421.                 guarda_files=false;
  422.                 }
  423.             }
  424.         if(guarda_files){
  425.             if(*(unsigned char*)&buffer[36]<=27 && /* length of volume name */
  426.                 (*(short*)&buffer[12]>1 ||        /* files in root directory, e il primo è il Desktop */
  427.                 (*(short*) buffer== 0x4244 &&*(short*)&buffer[82]>0)) ){    /* folders in root directory */
  428.                 ParamText(in_Italia?
  429.                 "\pQuesto disco contiene files in formato Macintosh, verranno sovrascritti":
  430.                 "\pThis disk contains some Macintosh files, their data will be overwritten",
  431.                 PNS,PNS,PNS);
  432.                 if( my_modal_dialog(133,miei_titoli,2) ==2){
  433.                     if(!n)de_Mac_ize(buffer);
  434.                     return 0;
  435.                     }
  436.                 if(n) return -1;
  437.                 }
  438.             else{
  439.                 if(!n) de_Mac_ize(buffer);
  440.                 return 2;
  441.                 }
  442.             }
  443.         chiedi_altro_disco();
  444.         }
  445.     else
  446.         return 1;
  447.     }
  448. }
  449.  
  450. void de_Mac_ize(buffer)
  451. char buffer[512];
  452. /* the Finder keeps a copy of sector 2 in the sector before the last one, and
  453. PBMountVol (called by GetNextEvent) when sees a disk with an invalid sector 2
  454. (what happens for any tar disk with more than 1024 bytes of data on it)
  455. but a valid sector 2878 (or 1598 or whatever) tells it's a Mac disk. (At first,
  456. we believed that the cause were tags, but a technical note explained that tags
  457. are no more required by the file system, hence they do not exist in drive where
  458. the hardware doesn't provide them, and the MFM format doesn't have tags).
  459. So it's better to deMac-ize disks when creating an archive. I prefer NOT to do
  460. that when sector 2 was overwritten by the UNIX tar, which obviously does not know
  461. about the Mac and the Finder, in that case in order to de-Macize I should write
  462. to the disk even if the user asked only to read, not a good thing
  463. */
  464. {
  465. leggi_settore(sectors_on_floppy-2,buffer);
  466. if(err_code) return;
  467. if(*(short*) buffer== 0xD2D7 || *(short*) buffer== 0x4244 )
  468.     buffer[0]++;    /* it's better to preserve everything, only change the
  469.                     code */
  470. write_sectors(sectors_on_floppy-2,buffer,1);    /* non-buffered write */
  471. di.disk_code=noMacDskErr;
  472. }
  473.  
  474. void write_tar_volume_header()
  475. /* writes the 'M' continuation header on GNU tar volumes following the first one */
  476.  
  477. {
  478. tarh_type buffer;
  479. long old_size,delta_size;
  480. short i;
  481.  
  482. /* get the needed data, which were saved when writing the last normal header */
  483. mcopy(&buffer,ultimo_header,sizeof(ultimo_header));
  484. fillmem(&buffer.name[sizeof(ultimo_header)],0,512-sizeof(ultimo_header));
  485. old_size=untar_number(buffer.size,-1);
  486. fillmem(buffer.size, '\0', 12);
  487.  
  488. delta_size = (long)avail_sectors_for_file<<9;
  489. last_offset += delta_size;
  490.  
  491. if(old_size<=delta_size) return;    /* il file terminava proprio 
  492.             nell'ultimo settore del disco precedente
  493.             -- the file happened to end in the last sector of the previous disk,
  494.             hence this disk must not contain an 'M' continuation header
  495.             */
  496.  
  497. numstr(&buffer.size, old_size-delta_size, 12);
  498. numstr(&buffer.offset, last_offset, 12);
  499. buffer.linkflag = 'M';
  500. fill_uname(&buffer);
  501. fill_checksum(&buffer);
  502.  
  503. /* update the saved informations */
  504. copia_ultimo_header(&buffer,(sector_t)1);
  505.  
  506. /* last_offset l'ho già calcolato */
  507. ultimo_disco_espulso=true;    /* forse... bisogna vedere come ritrovo l'header da 
  508.     azzerare in tronca_archivio !!!
  509.     -- unused variable, but in the future it should serve to help clearing
  510.     the last_header in case of error
  511.     */
  512.  
  513. scrivi_settore(last_sector,&buffer);
  514. check_wr_err();
  515. last_sector++;
  516. }
  517.  
  518. static void write_GNU_V_header()
  519. {
  520. tarh_type buffer;
  521. long curr_time;
  522. fillmem(&buffer.name,0,512);
  523. buffer.linkflag = 'V';
  524. strcpy(buffer.name,volLabel);
  525. strcat(buffer.name," Volume ");    /* the real GNU tar writes the volume number
  526.                                 only for multivolume archives, but suntar selects
  527.                                 the files interactively and can't know in advance
  528.                                 whether it will get a single-volume archive */
  529. my_itoa((long)++label_n,&buffer.name[strlen(buffer.name)]);
  530.  
  531. GetDateTime(&curr_time);
  532. numstr(&buffer.mtime, curr_time - UNIXTIME, 12);
  533. fill_checksum(&buffer);
  534.  
  535. scrivi_settore(last_sector,&buffer);    /* last_sector is surely 0 */
  536. check_wr_err();
  537. last_sector++;
  538. }
  539.  
  540.  
  541. static void set_bar_date()
  542. /* read the current date an time and store it in the format of the date field
  543. of the volme header for bar archives */
  544. {
  545. DateTimeRec cdate; 
  546. register char*p = bar_date;
  547. register short i;
  548.  
  549. GetTime (&cdate);
  550. cdate.year %= 100;    /* solo le ultime due cifre dell'anno... */
  551. for(i=0;i<5;i++){
  552.     *p++ = '0'+ ((short*)&cdate.year)[i] /10;
  553.     *p++ = '0'+ ((short*)&cdate.year)[i] %10;
  554.     }
  555. *p='\0';
  556. }
  557.  
  558. void write_bar_volume_header()
  559. {
  560. /* when there were doubts about what should be written (see untar.c)
  561. I preferred to write clean information rather than to follow the
  562. silly rules of the original bar: there seems to be no compatibility
  563. problem, since bar ignores the contents of the fields which it
  564. writes in a silly way
  565. */
  566. barh_type buffer;
  567. register long oldsize;
  568. short i;
  569.  
  570. fillmem(&buffer,0,512);
  571. my_itoa(my_uid,&buffer.uid);
  572. my_itoa(my_gid,&buffer.gid);
  573. buffer.bar_magic[0]='V';
  574. buffer.bar_magic[1]='\0';
  575. my_itoa((long)floppy_n,&buffer.volume_num);
  576. buffer.compressed='0';
  577. mcopy(&buffer.cdate,bar_date,12);
  578. strcpy(buffer.name,volLabel);
  579.  
  580. if(floppy_n==1)
  581.     oldsize = 0L;
  582. else{
  583.     oldsize = untar_number(((barh_type*)ultimo_header)->size,-1);
  584.     oldsize = (oldsize+511)>>9;        /* numero di settori necessari */
  585.     oldsize -= avail_sectors_for_file;    /* meno quelli già usati 
  586.             -- size = number of needed sectors at the time of the last header
  587.                 minus number of available sectors on previous disk
  588.             */
  589.     avail_sectors_for_file += sectors_on_floppy-1;
  590.     }
  591.  
  592. numstr(buffer.size, oldsize<<9, 12);
  593. bar_checksum(&buffer);
  594.  
  595. scrivi_settore(0,&buffer);
  596. check_wr_err();
  597. last_sector=1;
  598. }
  599.  
  600. short bar_header(fname, fsize, barh)
  601.   char *fname;
  602.   long fsize;
  603.   register barh_type *barh;
  604. {
  605.     fillmem(barh, 0, 512);
  606.     mac_to_unix(barh->name, fname+path_len);
  607.     if(!strcmp("./",barh->name) || !barh->name[0] ) return -1;        /* succede nel system 7.0 se 
  608.                  come folder da salvare seleziono un volume
  609.                 -- I get that string in System 7, a whole volume such as "HD40"
  610.                 becomes "./", but it's better not to save any entry for "HD40" !
  611.                 */
  612.  
  613.     if (statb.ioFlAttrib & ioDirMask)
  614.         if (barh->name[strlen(barh->name)-1] != '/')
  615.             barh->name[strlen(barh->name)] = '/';
  616.     numstr(barh->mode, (long)((statb.ioFlAttrib & ioDirMask) ? dirmode : filemode), 8);
  617.     numstr(barh->uid, my_uid, 8);
  618.     numstr(barh->gid, my_gid, 8);
  619.     numstr(barh->size, fsize, 12);
  620.     numstr(barh->mtime, (long) statb.ioFlMdDat - UNIXTIME, 12);
  621.     barh->linkflag = ((statb.ioFlAttrib & ioDirMask) ? '\0' : '0');    /* it's not clear
  622.         what I should write here, see the discussion un untar.c */
  623.     bar_checksum(barh);
  624.     questo_e_un_header=true;
  625.     writeblock(barh, 512);
  626.     last_header=last_sector-1;    /* ho bisogno di last_sector NON ancora incrementato
  627.             al settore successivo, ma incrementato degli eventuali header extra !
  628.             -- last_sector was already incremented, and I can't get the value before
  629.             calling write_block since it may add a volume header */
  630.     copia_ultimo_header(barh,last_sector);    /* last_sector incrementato */
  631.     return 0;
  632. }
  633.  
  634. void bar_checksum(buf)
  635. char *buf;
  636. {
  637. register short i;
  638. register long chk= ' '*8;
  639. for(i=0;i<48;++i)
  640.     chk += (unsigned char) buf[i];
  641. for (i+=8; i < 512; ++i)
  642.     chk += (unsigned char) buf[i];
  643. numstr(((barh_type*)buf)->chksum,chk,8);
  644. }
  645.  
  646. void writeblock(p,len)
  647. register char*p;
  648. short len;
  649. {
  650. if(len>=more_space){
  651.     mcopy(&disk_buffer[512-more_space],p,more_space);
  652.     p+=more_space;
  653.     len-=more_space;
  654.     write_next_sector();
  655.     last_sector++;
  656.     more_space=512;
  657.     check_events();
  658.     if(!len) return;
  659.     }
  660. mcopy(&disk_buffer[512-more_space],p,len);
  661. more_space-=len;
  662. }
  663.  
  664. unsigned char get_linkflag(length,doerror)
  665. long *length;
  666. short doerror;
  667. {
  668. unsigned char linkflag;
  669.     if(bar_archive){
  670.         linkflag=guess_bar_linkflag();
  671.         if( (*length=untar_number( ((barh_type*)disk_buffer)->size,doerror)) ==-1)
  672.             return 0xFF;
  673.         if(linkflag=='1'||linkflag=='5') *length=0;
  674.         }
  675.     else{
  676.         /* for directories, the size field may be used to store some informations,
  677.         hence I can't rely on it being 0 */
  678.         linkflag=((tarh_type*)disk_buffer)->linkflag;
  679.         if(linkflag=='5' || ((tarh_type*)disk_buffer)->name[
  680.             strlen(((tarh_type*)disk_buffer)->name)-1] == '/'){
  681.             linkflag='5';
  682.             *length=0;
  683.             }
  684.         else if(linkflag=='V')
  685.             *length=0;
  686.         else{
  687.             if( (*length=untar_number(((tarh_type*)disk_buffer)->size,doerror)) ==-1)
  688.                 return 0xFF;
  689.             }
  690.         }
  691.     return linkflag;
  692. }
  693.  
  694.  
  695. void cerca_fine()    /* find the end of the archive: used for Append */
  696. {
  697. long length;
  698. enum formats fmt;
  699. Boolean message_given=false;
  700.  
  701. previousFormat=tar_unknown;
  702. listonly=1;        /* don't use buffering */
  703. fmt=identify_format();
  704. if(fmt==tar_format){
  705.     bar_archive=false;
  706.     if( hasVheader || ((tarh_type*)disk_buffer)->linkflag=='M' ) {
  707.         previousFormat=tar_GNU;    /* se è già
  708.                 multivolume, vuol dire che il GNU tar è disponibile...
  709.                 -- if it's already GNU multivolume, later I must not bother the
  710.                 user asking if I may create a multivolume archive, and I must
  711.                 use the GNU format even if the current setting of tar_version
  712.                 is AIX */
  713.         if(hasVheader) last_header=1;
  714.         }
  715.     floppy_n=1;
  716.     }
  717. else if(fmt==bar_format){
  718.     bar_archive=true;
  719.     floppy_n=untar_dec_number( ((barh_type*)disk_buffer)->volume_num,true);
  720.     mcopy(bar_date,((barh_type*)disk_buffer)->cdate,12);
  721.     last_header= (untar_number( ((barh_type*)disk_buffer)->size,true)+1023)>>9;
  722.     }
  723. else
  724.     raise_error();
  725.  
  726. for(;;){
  727.     static char sita[]=" (dovresti assegnare l\'opzione \"tar version\")\n",
  728.                 sing[]=" (you should set the \"tar version\" option)\n",
  729.                 snew[]="\n";
  730.     register unsigned char linkflag;
  731.     disable_autoflush(1);
  732.     while(last_header>=sectors_on_floppy){
  733.         if(fmt==bar_format||previousFormat==tar_GNU||previousFormat!=tar_AIX&&tar_version==tar_GNU){
  734.             Boolean opt_ok= fmt==bar_format||tar_version==tar_GNU;
  735.             if(in_Italia)
  736.                 printf("La fine dell\'archivio non è in questo disco%s",opt_ok||message_given ? snew : sita);
  737.             else
  738.                 printf("The end of archive is not in this disk%s\n",opt_ok||message_given ? snew : sing);
  739.             message_given=true;
  740.             raise_error();
  741.             }
  742.         else{    /* potrebbe essere AIX...
  743.                 -- it could be AIX, but maybe the user has not set the option
  744.                 and in that case suntar suggests him to do that */
  745.             short i;
  746.             Boolean was_AIX;
  747.             last_header-=sectors_on_floppy;
  748.             do{
  749.                 diskEject();
  750.                 i=aspetta_inserzione(in_Italia?
  751.                     "\pInserisci il prossimo disco tar":"\pInsert next tar disk",false);
  752.                 if(i) raise_error();
  753.                 }
  754.             while(di.is_not_initialized);
  755.             was_AIX=previousFormat==tar_AIX;
  756.             i = tar_check_settore0(false);
  757.             if(i==-1){        /* bad header, but it's the normal case for AIX disks
  758.                             following the first one */
  759.                 if(previousFormat<=tar_singlevol&&tar_version!=tar_AIX){
  760.                     start_of_line();
  761.                     if(in_Italia)
  762.                         printf("Probabile formato AIX%s",message_given?snew:sita);
  763.                     else
  764.                         printf("Probable AIX format%s",message_given?snew:sing);
  765.                     message_given=true;
  766.                     }
  767.                 previousFormat=tar_AIX;
  768.                 }
  769.             else if(previousFormat==tar_GNU){        /* it was not so when entering in
  770.                     this while, but check_settore_0 may assign it */
  771.                 if(was_AIX) error_message("Not a AIX tar disk !\n");
  772.                 if(in_Italia)
  773.                     printf("Formato GNU tar%s",message_given?snew:sita);
  774.                 else
  775.                     printf("GNU tar format%s",message_given?snew:sing);
  776.                 message_given=true;
  777.                 last_header= hasVheader ? 1 : 0;
  778.                 }
  779.             }
  780.         }
  781.     check_events();
  782.     leggi_settore(last_header,disk_buffer);
  783.     if(check_error()) raise_error();
  784.  
  785.     last_sector=last_header;
  786.     if(check_all_zero(disk_buffer)){
  787.         if(last_header==0||(bar_archive||hasVheader)&&last_header==1)
  788.             printf(in_Italia?"Disco vuoto\n":"No files on disk\n");
  789.         enable_autoflush();
  790.         return;
  791.         }
  792.     linkflag= get_linkflag(&length,true);
  793.     if(linkflag!='1'&&linkflag!='2'&&linkflag!='V'&&linkflag!='M')
  794.         print_info(bar_archive ? ((barh_type*)disk_buffer)->name :
  795.             ((tarh_type*)disk_buffer)->name,length);
  796.     last_header += (length+1023)/512;
  797.     }
  798. }
  799.  
  800. void svuota_buffer()    
  801. /* empty the buffer, used at the end of a file, next data
  802. will be a file header which must be aligned at the start of a sector;
  803. really, it's useful only for MacBinary files, since tardata internally
  804. groups the data in 512 bytes chunks
  805. */
  806. {
  807. if(more_space!=512){
  808.     /* succede solo per MacBinary, visto che tardata scrive comunque in blocchi di 512 */
  809.     fillmem(&disk_buffer[512-more_space],0,more_space);    /* azzera quello che resta: 
  810.                 il tar per UNIX non lo fa, ma non è bello lasciare della robaccia...
  811.                 -- clear the empty part of the buffer before writing it out: the
  812.                 UNIX tar doesn't do that, but it's not professional to write
  813.                 garbage data (well, the Macintosh too does that, the 128 bytes
  814.                 of reserved data in the resource fork are garbage: but, think
  815.                 what would happen if that garbage happens to be a part of your
  816.                 personal mail, or reserved informations... The reserved bytes in
  817.                 the suntar application often happen to contain a chunk of its source
  818.                 code, which was saved before compiling and is still in the disk 
  819.                 buffer)
  820.                 */
  821.     write_next_sector();
  822.     last_sector++;
  823.     }
  824. more_space=512;
  825. }
  826.  
  827. void azzera_settore()    /* clear a sector, that is write an end of archive header */
  828. {
  829. svuota_buffer();
  830. fillmem(disk_buffer, 0, 512);
  831. questo_e_un_header=true;
  832. write_next_sector();
  833. /* niente last_sector++, per ovvie ragioni
  834. -- don't increment last_sector, another write must overwrite this sector
  835. */
  836. last_header=last_sector;
  837. }
  838.  
  839. void tronca_archivio()
  840. /* truncate an archive, by clearing the last header: used when,
  841. due to an error, what follows that header can't be completed */
  842. {
  843. last_sector=last_header;
  844. /* multivolume, se il disco è stato espulso deve richiederlo !!
  845. o forse non lo faccio qui, ma nella gestione setjmp, questa qui è chiamata anche 
  846. in caso di quit
  847. o forse dare un messaggio, in fondo capita raramente...
  848. -- in multivolume archives, the sector to be cleared may be on another disk,
  849. which was ejected. The correct behaviour should be to ask the user to insert
  850. back that disk, carefully check that it's the right disk and clear the sector,
  851. or, if the user refuses to insert it back, print which sector (and file) 
  852. must be cleared. By now, in that case I do nothing
  853. */
  854. /*printf("<%ld>",(long)last_sector);*/
  855.     /* I may avoid to flush things which are AFTER the last header: not only that
  856.     saves time, but if the operation was interrupted because that's the wrong
  857.     disk it could save good data */
  858. invalid_after(last_sector);
  859.  
  860. read_sectors(last_sector,disk_buffer,1);    /* don't use the value stored in the buffers! */
  861. if(err_code==0){
  862.     /* compare it with the stored content of the last sector: it would be
  863.     terrible to clear a sector in a disk which happens to be in that drive
  864.     but is not the tar/bar disk I was writing !
  865.     */
  866.     if(compare_mem(ultimo_header,disk_buffer,sizeof(ultimo_header))){
  867.         fillmem(disk_buffer, 0, 512);
  868.         scrivi_settore(last_sector,disk_buffer); /* senza verifica di errore */
  869.         flush_buffers();
  870.         }
  871.     else
  872.         invalid_buffers();
  873.     }
  874. else
  875.     invalid_buffers();
  876. more_space=512;
  877. }
  878.  
  879. Boolean compare_mem(p,q,s)
  880. register char*p,*q;
  881. register short s;
  882. {
  883. while(s){
  884.     if(*p++ != *q++) return false;
  885.     s--;
  886.     }
  887. return true;
  888. }
  889.  
  890. void print_ready()
  891. {
  892. long sz=sectors_on_floppy-last_header-1;
  893. printf("%ld",sz/2);
  894. if(sz&1)printf(in_Italia?",5":".5");
  895. printf(in_Italia?" Kbytes disponibili\n":" Kbytes available\n");
  896. }
  897.  
  898. /********************************/
  899.  
  900. void check_and_eject()
  901. /* eseguita in caso di QUIT ma anche in caso di errore
  902. -- executed in case of error or Quit
  903. */
  904. {
  905. if(write_in_corso){
  906.     tronca_archivio();
  907.     write_in_corso=false;
  908.     }
  909. else{
  910.     if(dirty_buffers()) invalid_buffers();
  911.     }
  912. diskEject();
  913. }
  914.  
  915. /************************/
  916. void check_wr_err()
  917. {
  918. if(err_code){
  919.     start_of_line();
  920.     if(err_code==-65)
  921.         printf(in_Italia?"Errore, disco assente\n":"Error, missing disk\n");
  922.     else
  923.         printf("Disk write error %d\n",err_code);
  924.     if(!ignore_errors && write_in_corso){
  925.         tronca_archivio();
  926.         raise_error();
  927.         }
  928.     }
  929. }
  930. /*********************************/
  931.  
  932. void my_tar(file_mode)    /* handles a command from the Write menu */
  933. short file_mode;
  934. {
  935. short charsRead;
  936.  
  937. short n_types;
  938. SFTypeList    myTypes;
  939. extern unsigned char*nomeFormato;
  940.  
  941. if(file_mode==wmSetLabel){
  942.     /* that's not a file format... */
  943.     ParamText(in_Italia?"\pNome da assegnare all\'archivio :":
  944.         "\pName assigned to the archive :",PNS,PNS,PNS);
  945.     my_edt_dialog(142,volLabel,bar_archive?99:99-10,"\p");
  946.     my_p2cstr(volLabel);
  947.     label_n=0;
  948.     return;
  949.     }
  950.  
  951. if(file_mode==wmASCII){
  952.     n_types=1;
  953.     myTypes[0]='TEXT';
  954.     binary=false;
  955.     dataonly=true;
  956.     nomeFormato="\p    (ASCII)";
  957.     }
  958. else if(file_mode==wmWriteTar){
  959.     if(bar_archive)
  960.         n_types=-1;
  961.     else
  962.         n_types=2;
  963.     myTypes[0]='TARF';
  964.     myTypes[1]='TEXT';    /* quelli estratti con MacCompress se provengono da UNIX
  965.                         (niente resource fork) sono TEXT KAHL
  966.                         -- .tar.Z files extracted with MacCompress are TEXT-KAHL,
  967.                         .tar files created by tar 3.0 are TARF TAR , those created
  968.                         by suntar may be TARF (copy to mac file) or TEXT (save sectors)
  969.                         */
  970.     }
  971. else{    /* wmDataFork o wmWriteMacBin */
  972.     n_types=-1;
  973.     binary=true;
  974.     dataonly= file_mode==wmDataFork;
  975.     nomeFormato=file_mode==wmWriteMacBin?"\p(MacBinary)":"\p(Data fork)";
  976.     }
  977.  
  978. more_space=512;
  979. if(file_mode!=wmWriteTar){
  980.     Str255 name;
  981.     short i=get_file_or_folder(name,n_types,&myTypes);
  982.     if(i<0) return;    /* cancel...*/
  983.     if(i==0){    /* folder: il nome è il path completo, ma non voglio 
  984.                 salvarlo tutto nell'archivio
  985.                 -- folder: discover the size difference between the full
  986.                 pathname and the partial pathname
  987.                 No more useful since now I use a partial file name anyway,
  988.                 but to keep these instructions causes no problems */
  989.         path_len=name[0]-1;    /*il -1 è necessario, in fondo c'è un : 
  990.                 -- the -1 is needed since the last character is a ':'
  991.                 */
  992.         while(path_len>0 && name[path_len]!=':') path_len--;
  993.         if(--path_len<0)path_len=0;    /*non dovrebbe mai capitare 
  994.                     -- that should never happen, but behaving well in cases
  995.                     that should be impossible may save a programmer from
  996.                     some nasty bugs */
  997.         }
  998.     else /* file semplice, il nome è relativo al volume
  999.         -- single file, I've filename + vRefNum as returned by SFGetFile
  1000.         */
  1001.         path_len=0;
  1002.     name[name[0]+1]=0;
  1003.     fase=writing_disk;
  1004.     write_in_corso=1;
  1005.     alias_prefix[0]='\0';
  1006.     tar_file_or_folder(&name[1]);
  1007.     azzera_settore();
  1008.     flush_buffers();
  1009.     write_in_corso=0;
  1010.     }
  1011. else{    /* file tar, non c'è da creare header o altro...
  1012.         -- write tar file: handle it directly here...
  1013.         */
  1014.     sector_t more_sectors=0;
  1015.     long length;
  1016.  
  1017.     my_SF_Get(n_types,myTypes);
  1018.     if(!reply.good)return;
  1019.     path_len=0;
  1020.  
  1021.     if(apri_file("rb",&inf_refn))
  1022.         return;
  1023.     inf_is_open=true;
  1024.     fase=writing_disk;
  1025.     write_in_corso=1;
  1026.     if(bar_archive){
  1027.         /* read (and skip) the volume header, with some checks */
  1028.         charsRead = mac_fread(disk_buffer, 512, inf_refn);
  1029.         if(charsRead<0) error_message_1(in_Italia?FERRORita:FERRORing,err_code);
  1030.         if(((barh_type*)disk_buffer)->bar_magic[0]!= 'V' || 
  1031.                ((barh_type*)disk_buffer)->bar_magic[1] != 0)
  1032.             error_message(in_Italia?"Questo non è un file in formato bar\n":
  1033.                 "Not a bar file !\n");
  1034.         if(floppy_n==0 && last_sector==0) mcopy(bar_date,((barh_type*)disk_buffer)->cdate,12);
  1035.         }
  1036.     do{
  1037.         charsRead = mac_fread(disk_buffer, 512, inf_refn);
  1038.         if(charsRead<0) error_message_1(in_Italia?FERRORita:FERRORing,err_code);
  1039.         if(charsRead>=0 && charsRead<512)
  1040.             fillmem(&disk_buffer[charsRead], 0, 512-charsRead); /* non indispensabile, 
  1041.                                     ma è brutto che lo spazio extra
  1042.                                     nell'ultimo settore del file resti garbage.
  1043.                                     -- see before, clear the buffer to avoid writing
  1044.                                     garbage at the end of the last sector
  1045.                                     */
  1046.         /* meglio non controllare errore, i file di tar2 sono cattivi e invece va poi 
  1047.         tutto bene...*/
  1048.         if(more_sectors==0){
  1049.             last_header=last_sector;
  1050.             if(charsRead==0 || check_all_zero(disk_buffer))
  1051.                 charsRead=0;    /* to exit the loop */
  1052.             else{
  1053.             /* it was an header: do the standard work for headers, extract the size 
  1054.             field and continue */
  1055.                 questo_e_un_header=true;
  1056.                 copia_ultimo_header(disk_buffer,last_sector+1);
  1057.                 last_offset=0;
  1058.                 (void)get_linkflag(&length,true);
  1059.                 if(length<0){
  1060.                     check_and_eject();
  1061.                     raise_error();
  1062.                     }
  1063.                 else{
  1064.                     more_sectors=(length+511)/512;
  1065.                     print_info(bar_archive?((barh_type*)disk_buffer)->name:disk_buffer,length);
  1066.                     if(!bar_archive) controlla_che_ci_stia(more_sectors);
  1067.                     }
  1068.                 }
  1069.             }
  1070.         else{
  1071.             if(charsRead==0)
  1072.                 error_message(in_Italia?"Archivio incompleto\n":"Incomplete archive\n");
  1073.             more_sectors--;
  1074.             }
  1075.         check_events();
  1076.         write_next_sector();
  1077.         last_sector++;
  1078.         }
  1079.     while(charsRead>0);
  1080.     flush_buffers();
  1081.     write_in_corso=0;
  1082.  
  1083.     FSClose(inf_refn);
  1084.     inf_is_open=false;
  1085.     last_sector=last_header;
  1086.     }
  1087. }
  1088.  
  1089.  
  1090. void close_input_files()
  1091. {    /* da chiamare in caso che una longjmp esca dalla routine precedente */
  1092. if(inf_is_open){
  1093.     FSClose(inf_refn);
  1094.     inf_is_open=false;
  1095.     }
  1096. if(devo_chiudere_in){
  1097.     (void) PBCloseSync(&pb);
  1098.     devo_chiudere_in=false;
  1099.     }
  1100. }
  1101.  
  1102. void FillMacBin2Fields()        /* transforms a MacBinary header into a MacBinary II header */
  1103. {
  1104. extern short current_crc;
  1105. register short i;
  1106.  
  1107. /* can't declare a pointer to binh_type since it's misaligned by one byte */
  1108. tarh.name[101]=tarh.name[74];        /* because I didn't clear that byte, as the
  1109.                     MacBinary standard says, but left there the finder flags which 
  1110.                     MacBinary II says must be stored elsewhere */
  1111. tarh.name[74]=0;    /* but now it's better to follow the standard */
  1112. tarh.name[122]=tarh.name[123]=129;
  1113. current_crc=0;
  1114. for(i=0;i<124;i++)
  1115.     CalcCRC(tarh.name[i]);
  1116. CalcCRC(0);
  1117. CalcCRC(0);
  1118. *(short*)&tarh.name[124]=current_crc;
  1119. }
  1120.  
  1121. void assegna_tar_version()
  1122. {
  1123. extern char *titoli[];
  1124.  
  1125. if(dirty_buffers()) flush_buffers();
  1126. tar_version=my_modal_dialog(140,NULL,0);
  1127.  
  1128. ParamText(in_Italia?
  1129.     "\pDevo assegnare l\'opzione \"tar version\" permanentemente ?":
  1130.     "\pSet the option \"tar version\" permanently ?",PNS,PNS,PNS);
  1131. if(my_modal_dialog(130,titoli,2)==1)
  1132.     save_options();
  1133. }
  1134.  
  1135.  
  1136. void controlla_che_ci_stia(n_sectors)
  1137. sector_t n_sectors;
  1138. /* check that there is enough space in the disk for next file: if not,
  1139. a multivolume archive could be generated, but the standard tar does not
  1140. accept multivolume archives
  1141. */
  1142. {
  1143. if(previousFormat<=tar_singlevol &&tar_version<=tar_singlevol &&
  1144.    last_header+n_sectors+1>=sectors_on_floppy){    /* l'header va nel 
  1145.             settore last_header, seguono n_sectors settori di dati fino a last_header +
  1146.             n_sectors e il settore last_header+n_sectors+1 deve contenere gli zeri di
  1147.             indicazione fine archivio */
  1148.     if(previousFormat==tar_unknown&&tar_version==tar_unknown){
  1149.         if(dirty_buffers()) flush_buffers();
  1150.         ParamText(in_Italia?
  1151.             "\pSpazio insufficiente, creo un archivio multidisco ?":
  1152.             "\pNot enough space, OK to create a multivolume archive ?",PNS,PNS,PNS);
  1153.         assegna_tar_version();
  1154.         }
  1155.  
  1156.     if(tar_version==tar_singlevol){
  1157.         printf(in_Italia?"Errore, spazio insufficiente\n":"Error, not enough space\n");
  1158.         /*tronca_archivio();    /* bisogna riazzerare l'ultimo header per avere un disco consistente */
  1159.         raise_error();    /* che chiama check_and_eject che chiama tronca_archivio, per cui
  1160.                 quella chiamata sopra non serve */
  1161.         }
  1162.     }
  1163. }
  1164.  
  1165. static void alias_error(err)
  1166. short err;
  1167. {
  1168. if(err!=noErr){
  1169.     beep_in_foreground();
  1170.     error_message_1("Error %d in resolving alias\n",err);
  1171.     }
  1172. }
  1173.  
  1174.  
  1175. /*********** end of routines by Speranza ****************/
  1176.  
  1177. /****** start of routines by Gail Zacharias *****************/
  1178.  
  1179.  
  1180. void tar_file_or_folder (file_name)
  1181.   char *file_name;
  1182. {
  1183.  
  1184. disable_autoflush(1);
  1185.  
  1186. statf(file_name);
  1187. if (statb.ioFlAttrib & ioDirMask) {
  1188.     statb.ioVRefNum = getvrefnum(file_name);
  1189.     tardir(file_name);
  1190.     }
  1191. else{
  1192.     char *cp = file_name+strlen(file_name);
  1193.     while (cp != file_name && cp[-1] != ':') --cp;
  1194.     if ((macbinh.nlen = strlen(cp)) >= 64) nametoolong(file_name);
  1195.     strcpy(macbinh.name, cp);
  1196.     tarfile(file_name);
  1197.     }
  1198. }
  1199.  
  1200. void tardir (dname)
  1201.   char *dname;
  1202. {
  1203.     short isvolume;
  1204.     Str255 name;
  1205.     long dirid = statb.ioDirID;
  1206.     short index = 0;
  1207.     short dlen = strlen(dname);
  1208.  
  1209.     isvolume = bar_archive ? bar_header(dname, 0L, &tarh) : tarheader(dname, 0L);
  1210.     if(!isvolume){
  1211.         if(expert_mode) print_sector_n(last_sector-1); /* -1 perché è già stato
  1212.             incrementato; potrei spostare la printf sopra, ma allora non saprei se è
  1213.             un volume... */
  1214.         printf(in_Italia?"Cartella %s\n":"Folder %s\n",
  1215.             bar_archive?((barh_type*)&tarh)->name:tarh.name);
  1216.         }
  1217.   
  1218.     if(strchr(dname, ':'))
  1219.         strcpy(name, dname);
  1220.     else{
  1221.         name[0] = ':';
  1222.         strcpy(&name[1], dname);
  1223.         dlen++;
  1224.         }
  1225.     if (name[dlen-1] != ':') name[dlen++] = ':';
  1226.     while (1) {
  1227.         statb.ioFDirIndex = ++index;
  1228.         statb.ioDirID = dirid;
  1229.         statb.ioNamePtr = &macbinh.nlen;
  1230.         if (PBGetCatInfoSync(&statb) || statb.ioResult) {
  1231.             if (statb.ioResult != fnfErr ) pbsyserr(&statb);
  1232.             return;
  1233.             }
  1234.         strncpy(&name[dlen], macbinh.name, macbinh.nlen);
  1235.         name[dlen+macbinh.nlen] = '\0';
  1236.         if (macbinh.nlen >= 64 ) nametoolong(name);
  1237.         if (statb.ioFlAttrib & ioDirMask) 
  1238.             tardir(name);
  1239.         else
  1240.             tarfile(name);
  1241.         }
  1242. }
  1243.  
  1244.  
  1245. void tarfile (fname)
  1246. /* heavily modified by Speranza, in order to handle aliases */
  1247.   char *fname;
  1248. {
  1249. char name[150];
  1250. short vrefnum=0;
  1251. short old_pl=path_len;
  1252. short old_as_len=strlen(alias_prefix);
  1253.  
  1254. extern char s_spazi[];
  1255.  
  1256. strcpy(name,fname);
  1257. if (statb.ioFRefNum) 
  1258.     printf("Warning: file %s was already open\n", name);
  1259.  
  1260. if( resolve_aliases && (statb.ioFlFndrInfo.fdFlags & ALIAS_BIT) ){
  1261.     if(! gHasResolveAlias){
  1262.         if(dirty_buffers()) flush_buffers();
  1263.         ParamText(in_Italia?"\pPer risolvere gli alias ci vuole il System 7":
  1264.         "\pAliases can\'t be resolved without System 7",PNS,PNS,PNS);
  1265.         my_alert();
  1266.         }
  1267.     else{
  1268.         FSSpec mySpec;
  1269.         WDPBRec param;
  1270.         char is_folder,is_aliased;
  1271.         short io,start;
  1272.  
  1273.         io=FSMakeFSSpec(0,0L,my_c2pstr(name),&mySpec);
  1274.         alias_error(io);
  1275.         my_p2cstr(name);
  1276.         io=strlen(name);
  1277.         while(io>0 && name[io-1]!=':') io--;
  1278.         if(!alias_prefix[0]){
  1279.             alias_prefix[0]=':';
  1280.             start=1;
  1281.             }
  1282.         else
  1283.             start=old_as_len;
  1284.         if(start+io<=99){
  1285.             if(name[0]==':')
  1286.                 mcopy(&alias_prefix[start],&name[1],--io);
  1287.             else
  1288.                 mcopy(&alias_prefix[start],&name[0],io);
  1289.             alias_prefix[start+io]='\0';
  1290.             }
  1291.  
  1292.         io=ResolveAliasFile(&mySpec,true,&is_folder,&is_aliased);
  1293.         if(io!=noErr){
  1294.             printf(in_Italia?"Alias %s: non trovato l\'originale\n":
  1295.             "Alias %s: original not found\n",name);
  1296.             alias_prefix[old_as_len]='\0';
  1297.             return;
  1298.             }
  1299. /* ora, il metodo regolamentare sarebbe fare
  1300. io=FSpOpenDF(&mySpec,fsRdPerm,&pb.ioRefNum);    (data fork)
  1301. io=FSpOpenRF(&mySpec,fsRdPerm,&pb.ioRefNum);    (resource fork)
  1302. ma tutto il programma è impostato sui vecchi formati: quale è il nuovo
  1303. equivalente di PBGetCatInfo ? Ovvero, come la si deve chiamare se si hanno
  1304. solo le informazioni vecchio stile ? Per ora preferisco tradurre la specifica nuova 
  1305. in una vecchia, forse il modo che uso non è il migliore ma per ora l'importante 
  1306. è che funzioni 
  1307. -- at this point, I have a FSSpec, while all the routines by Zacharias expect
  1308. the old couple vRefNum-filename
  1309. A conversion to the new style would be more elegant, a conversion to the old
  1310. style is more compatible and easier to implement, hence that's what I did
  1311. */
  1312.         if(is_folder){
  1313. #ifdef V_122
  1314.             PathNameFromDirID(mySpec.parID, mySpec.vRefNum, name);
  1315.             path_len=name[0]-1;    /* ci sarebbe da discutere che path name 
  1316.                         mettere nell'archivio, quello dell'alias o quello dell'
  1317.                         originale ? Così non ci metto nessun pathname, gli alias di
  1318.                         folder appaiono al livello esterno
  1319.                         -- which path must be written in the archive ? to remove
  1320.                         the problem, aliases are written with the last name only:
  1321.                         that's not the best solution, but it's simple to implement
  1322.                         */
  1323.             pStrcat(name,mySpec.name);
  1324.             pStrcat(name,"\p:");
  1325.             my_p2cstr(name);
  1326.             tar_file_or_folder (name);
  1327. #else
  1328.             short oldref;
  1329.             path_len=0;
  1330.             pStrcpy(name,"\p:");
  1331.             pStrcat(name,mySpec.name);
  1332.             pStrcat(name,"\p:");
  1333.             my_p2cstr(name);
  1334.             oldref=curr_vrefnum;
  1335.  
  1336.             param.ioVRefNum=mySpec.vRefNum;
  1337.             /*printf("FSSpec=%d %ld %P\n",mySpec.vRefNum,mySpec.parID,mySpec.name);*/
  1338.             param.ioNamePtr=NULL;
  1339.             param.ioWDProcID=signature;
  1340.             param.ioWDDirID=mySpec.parID;
  1341.             io=PBOpenWDSync(¶m);
  1342.             alias_error(io);
  1343.             curr_vrefnum=param.ioVRefNum;
  1344.             SetVol(NULL,curr_vrefnum);
  1345.             register_WD(param.ioVRefNum);
  1346.  
  1347.             /*printf("intero=%s pezzo=%s\n",name,name+path_len);*/
  1348.             tar_file_or_folder (name);
  1349.             SetVol(NULL,curr_vrefnum=oldref);
  1350. #endif
  1351.             path_len=old_pl;
  1352.             alias_prefix[old_as_len]='\0';
  1353.  
  1354.             return;
  1355.             }
  1356. /* ora mi creo una WD sul file origine: poi non la chiudo per lo stesso motivo
  1357. che in Untar (gestione duplicate file name)
  1358. -- PBGetCatInfo may be called without a working directory ID (by using PBHGetCatInfo),
  1359. but tardata and other routines expect a vrefnum, hence I create a working directory. */
  1360.         param.ioVRefNum=mySpec.vRefNum;
  1361.         param.ioNamePtr=NULL;
  1362.         param.ioWDProcID=signature;
  1363.         param.ioWDDirID=mySpec.parID;
  1364.         io=PBOpenWDSync(¶m);
  1365.         alias_error(io);
  1366.  
  1367.         vrefnum=param.ioVRefNum;    /* ad uso delle varie open...*/
  1368.         register_WD(param.ioVRefNum);
  1369.  
  1370.         /* fill the informations which statf should have returned */
  1371.         statb.ioNamePtr = mySpec.name;
  1372.         statb.ioFVersNum = 0;
  1373.         statb.ioVRefNum = param.ioVRefNum;
  1374.         statb.ioFDirIndex = 0;
  1375.         statb.ioDirID = 0;
  1376.         if (PBGetCatInfoSync(&statb) ) pbsyserr(&statb);
  1377.  
  1378.         statb.ioNamePtr = NULL;
  1379.         my_p2cstr(mySpec.name);
  1380.         strcpy(name,mySpec.name);
  1381.         path_len=0;
  1382.         }
  1383.     }
  1384.  
  1385.  
  1386. if (dataonly){
  1387.     if(binary || (statb.ioFlFndrInfo.fdType == 'TEXT'&&!(statb.ioFlFndrInfo.fdFlags&ALIAS_BIT)))
  1388.         tardata(name,vrefnum);
  1389.     else    /* Write ASCII on non-text files */
  1390.         switch(non_text_ASCII){
  1391.         case 0:    /* not saved */
  1392.             if(expert_mode) printf(s_spazi);
  1393.             printf("File %s (%s)\n",name+path_len,in_Italia?"non salvato":"not saved");
  1394.             break;
  1395.         case 1:    /* data */
  1396.             binary=1;
  1397.             tardata(name,vrefnum);
  1398.             binary=0;
  1399.             break;
  1400.         case 2:    /* ASCII */
  1401.             tardata(name,vrefnum);
  1402.             break;
  1403.         case 3:    /* macbinary */
  1404.             tarmacbin(name,vrefnum);
  1405.             break;
  1406.         }
  1407.     }
  1408. else
  1409.     tarmacbin(name,vrefnum);
  1410. path_len=old_pl;
  1411. alias_prefix[old_as_len]='\0';
  1412. svuota_buffer();        /* per approssimare per eccesso a multipli di 512 bytes... */
  1413. }
  1414.  
  1415.  
  1416. void tardata (fname,vrefnum)
  1417.   char *fname;
  1418.   short vrefnum;
  1419. {
  1420.     if(bar_archive)
  1421.         bar_header(fname, statb.ioFlLgLen, &tarh);
  1422.     else
  1423.         tarheader(fname, statb.ioFlLgLen);
  1424.     if(expert_mode) print_sector_n(last_sector-1);
  1425.  
  1426.     printf("File %s (%ld bytes)",bar_archive?((barh_type*)&tarh)->name:tarh.name, 
  1427.         statb.ioFlLgLen);
  1428.     if(!binary) printf(" ASCII\n"); else printf("\n");
  1429.     if(statb.ioFlLgLen>=FLUSH_MIN_SIZE) flush_console();
  1430.  
  1431.     pb.ioParam.ioVRefNum = vrefnum;
  1432.     pb.ioParam.ioVersNum = 0;
  1433.     pb.ioParam.ioPermssn = fsRdPerm;
  1434.     pb.ioParam.ioMisc = 0;
  1435.     pb.ioParam.ioNamePtr = my_c2pstr(fname);
  1436.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  1437.  
  1438.     devo_chiudere_in=true;
  1439.     tar_writefork(statb.ioFlLgLen, 0);
  1440.     my_p2cstr(fname);
  1441. }
  1442.  
  1443. void tarmacbin(fname,vrefnum)
  1444.   char *fname;
  1445.   short vrefnum;
  1446. {
  1447.     long fsize = macbinsz(statb.ioFlLgLen)+macbinsz(statb.ioFlRLgLen)+128L;
  1448.     if(bar_archive)
  1449.         bar_header(fname, fsize, &tarh);
  1450.     else
  1451.         tarheader(fname, fsize);
  1452.     if(expert_mode) print_sector_n(last_sector-1);
  1453.  
  1454.     printf("MacBinary %s (data %ld+res %ld bytes)\n",
  1455.                 bar_archive ? ((barh_type*)&tarh)->name : tarh.name,
  1456.                 statb.ioFlLgLen, statb.ioFlRLgLen);
  1457.     if(statb.ioFlLgLen+statb.ioFlRLgLen>=FLUSH_MIN_SIZE) flush_console();
  1458.     macbinheader();
  1459.     pb.ioParam.ioVRefNum = vrefnum;
  1460.     pb.ioParam.ioVersNum = 0;
  1461.     pb.ioParam.ioPermssn = fsRdPerm;
  1462.     pb.ioParam.ioMisc = 0;
  1463.     pb.ioParam.ioNamePtr = my_c2pstr(fname);
  1464.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  1465.     devo_chiudere_in=true;
  1466.     tar_writefork(statb.ioFlLgLen, 1);
  1467.     pb.ioParam.ioVRefNum = vrefnum;
  1468.     pb.ioParam.ioVersNum = 0;
  1469.     pb.ioParam.ioPermssn = fsRdPerm;
  1470.     pb.ioParam.ioMisc = 0;
  1471.  
  1472. #define ioDirID ioFlNum
  1473.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  1474.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  1475.         pb.ioParam.ioNamePtr=mac_file_name;
  1476.         }
  1477. #undef ioDirID        /* must not conflict with statb.ioDirID */
  1478.  
  1479.     if (PBHOpenRFSync(&pb)) pbsyserr(&pb);
  1480.     devo_chiudere_in=true;
  1481.     tar_writefork(statb.ioFlRLgLen, 2);
  1482.     /* if (fsize & 511L) writeblock(&tarh, 512 - (fsize & 511L));
  1483.         NO, ci deve pensare svuota_buffer */
  1484.     my_p2cstr(fname);
  1485. }
  1486.  
  1487. void macbinheader()
  1488. {
  1489.  
  1490.   fillmem(&macbinh.name[macbinh.nlen], 0, 64+63-macbinh.nlen);    
  1491.       /* anche i campi che seguono vanno azzerati... */
  1492.   mcopy(&macbinh.finfo, &statb.ioFlFndrInfo, sizeof(FInfo));
  1493.   macbinh.protected = 0;
  1494.   macbinh.zero = 0;
  1495.   macbinh.dflen = statb.ioFlLgLen;
  1496.   macbinh.rflen = statb.ioFlRLgLen;
  1497.   macbinh.cdate = statb.ioFlCrDat;
  1498.   macbinh.mdate = statb.ioFlMdDat;
  1499.   tarh.name[0]=0;
  1500.   mcopy(&tarh.name[1], &macbinh, sizeof(macbinh));
  1501.   FillMacBin2Fields();
  1502.   writeblock(&tarh, 128);
  1503. }
  1504.  
  1505. void tar_writefork (fsize, macbinp)
  1506.   long fsize;
  1507.   short macbinp;
  1508. {
  1509.   unsigned short n_non_ASCII=0;
  1510.   short blocksz = (macbinp ? 128 : 512);
  1511.   pb.ioParam.ioPosMode = fsAtMark;
  1512.   pb.ioParam.ioBuffer = (Ptr) &tarh;
  1513.   pb.ioParam.ioReqCount = blocksz;
  1514.   while (fsize) {
  1515.     if (fsize < pb.ioParam.ioReqCount)
  1516.         pb.ioParam.ioReqCount = fsize;
  1517.     fsize -= pb.ioParam.ioReqCount;
  1518.     if (PBReadSync(&pb) || pb.ioParam.ioActCount != pb.ioParam.ioReqCount) {
  1519.       short err = pb.ioParam.ioResult;
  1520.       (void) PBCloseSync(&pb);
  1521.       devo_chiudere_in=false;
  1522.       pb.ioParam.ioResult = err;
  1523.       pbsyserr(&pb);
  1524.     }
  1525.     if (!macbinp && !binary) {
  1526.       register char *cp = pb.ioParam.ioBuffer;
  1527.       register short i = pb.ioParam.ioActCount;
  1528.       while (i) {
  1529.         if (*cp == CR) *cp = LF;
  1530.         else if( (unsigned char) *cp >= 128 )
  1531.             n_non_ASCII++;
  1532.         --i, ++cp;
  1533.       }
  1534.     }
  1535.     if(pb.ioParam.ioActCount<blocksz)
  1536.         fillmem(&pb.ioParam.ioBuffer[pb.ioParam.ioReqCount],0,blocksz-(short)pb.ioParam.ioActCount);  /* il tar
  1537.         per UNIX non lo fa, ma è talmente sporco non farlo */
  1538.     writeblock(pb.ioParam.ioBuffer, blocksz);
  1539.   }
  1540.   if(macbinp==1)
  1541.     get_openfile_location(pb.ioParam.ioRefNum);
  1542.  
  1543.   if (PBCloseSync(&pb)) pbsyserr(&pb);
  1544.   devo_chiudere_in=false;
  1545.   if(n_non_ASCII != 0) printf(in_Italia?"Scritti %u caratteri non ASCII\n":
  1546.       "%u non-ASCII characters were written\n",n_non_ASCII);
  1547. }
  1548.  
  1549. short tarheader (fname, fsize)
  1550.   char *fname;
  1551.   long fsize;
  1552. {
  1553.     long n_sectors=(fsize+511)/512;
  1554.  
  1555.     fillmem(&tarh, 0, 512);
  1556.     mac_to_unix(tarh.name, fname+path_len);
  1557.     if(!strcmp("./",tarh.name) || !tarh.name[0] ) return -1;
  1558.     if (statb.ioFlAttrib & ioDirMask)
  1559.     if (tarh.name[strlen(tarh.name)-1] != '/')
  1560.         tarh.name[strlen(tarh.name)] = '/';
  1561.     numstr(&tarh.mode, (long)((statb.ioFlAttrib & ioDirMask) ? dirmode : filemode), 8);
  1562.     numstr(&tarh.uid, my_uid, 8);
  1563.     numstr(&tarh.gid, my_gid, 8);
  1564.     numstr(&tarh.size, fsize, 12);
  1565.     numstr(&tarh.mtime, (long) statb.ioFlMdDat - UNIXTIME, 12);
  1566.     tarh.linkflag = ((statb.ioFlAttrib & ioDirMask) ? '5' : '0');
  1567.     fill_uname(&tarh);
  1568.     fill_checksum(&tarh);
  1569.     last_offset=0;
  1570.     questo_e_un_header=true;
  1571.     writeblock(&tarh, 512);
  1572.     last_header=last_sector-1;    /* mi serve il valore pre-incremento, ma eventuali
  1573.                 header di volume devono essere contati... */
  1574.  
  1575. /* remember what you are going to write: it's useful for the 'M' continuation
  1576. header, and also for checks before clearing this same sector later if
  1577. I can't successfully save on disk the whole file
  1578. */
  1579.     copia_ultimo_header(&tarh,last_sector);    /* valore post-incremento */
  1580.     controlla_che_ci_stia((short)n_sectors);
  1581.     return 0;
  1582. }
  1583.  
  1584. static void fill_uname(t)
  1585. tarh_type *t;
  1586. {
  1587.     if(uname[0]||gname[0]){
  1588.         strcpy(t->magic, "ustar  ");
  1589.         strcpy(t->uname, uname);
  1590.         strcpy(t->gname, gname);
  1591.         }
  1592. }
  1593.  
  1594. void fill_checksum(t)
  1595. register tarh_type *t;
  1596. {
  1597.     register long chksum = 0;
  1598.     register short i;
  1599.     fillmem(t->chksum, ' ', 8);
  1600.         for(i=0; i<512; ++i) chksum += (unsigned char)t->name[i];
  1601.     numstr(t->chksum, chksum, 8);
  1602. }
  1603.  
  1604. /* Don't allow absolute names.   "HD:foo:bar" becomes "./foo/bar" */
  1605. void mac_to_unix(uname, mname)
  1606. char *uname, *mname;
  1607. {
  1608.   register char *up = uname, *cp;
  1609.   register unsigned char c;
  1610.   register short namelen;
  1611.   char buffer[100];
  1612.  
  1613. if(alias_prefix[0] && strlen(alias_prefix)+strlen(mname)<100){
  1614.     if(alias_prefix[strlen(alias_prefix)-1]==':'  && mname[0]==':')
  1615.         /* alias_prefix always terminates by ':', but testing that does not harm */
  1616.         mname++;
  1617.     strcpy(buffer,alias_prefix);
  1618.     strcat(buffer,mname);
  1619.     mname=buffer;
  1620.     }
  1621.  
  1622.   if (cp = strchr(mname, ':')) {
  1623.   #ifdef DOT_SLASH_NAME
  1624.       *up++ = '.', *up++ = '/';
  1625.   #endif
  1626.        ++cp;
  1627.        }
  1628.   else
  1629.       cp = mname;
  1630.  
  1631.   for(;;) {
  1632.     while (*cp == ':') *up++ = '.', *up++ = '.', *up++ = '/', ++cp;
  1633.     namelen=0;
  1634.     while (*cp && *cp != ':'){
  1635.         /* modified by Speranza to handle in some way non-ASCII codes 128 and upper,
  1636.         and characters which the UNIX shell uses.
  1637.         */
  1638.         c=*cp++;
  1639.  
  1640.         if(c>=127){
  1641.             static char s1[]="ÄÖäößÆæŒœ™";
  1642.             static char s2[]="©ØøÀÃÕÿƒ";
  1643.             char *p;
  1644.             if((p=strchr(s1,c))){    /* special characters with a two-character transliteration */
  1645.                 if(!trunc_14 || namelen<14)
  1646.                     *up++="AOaosAaOot"[p-s1];
  1647.                 namelen++;
  1648.                 c=    "eeeeseeeem"[p-s1];
  1649.                 }
  1650.             else if(c>=128 && c<160)    /* remove accents, tilde etc. */
  1651.                 c= "AACENOUaaaaaaceeeeiiiinooooouuuu"[c-128];
  1652.             else if((p=strchr(s2,c)))
  1653.                 c= "cOoAAOyf"[p-s2];
  1654.             else if( (c==208 || c==209) && namelen!=0)
  1655.                 c='-';
  1656.             else if(c==202&&!suppress_shell_chars)    /* non-breakable space */
  1657.                 c=' ';
  1658.             else
  1659.                 c='\0';
  1660.             }
  1661.         else if(suppress_shell_chars){
  1662.                 /* many characters have a special meaning to the UNIX shell, but some
  1663.                 only when used as first character of an identifier.
  1664.                 Really we're not so expert of UNIX to know the better thing to do with
  1665.                 every character under every shell and/or file utility: the rule which
  1666.                 is often given is "use only letters, digits, underscore and dot" but
  1667.                 a few other characters are usually good */
  1668.             if(c==' ')
  1669.                 c='_';
  1670.             else if(strchr(";|^*?\'\\`\"!$@<>&()[],",c) )
  1671.                 c= '\0';
  1672.             else if(namelen==0 && strchr("~%-.#",c) )
  1673.                 c= '\0';
  1674.             }
  1675.         if (c<' '){
  1676.             #define REPLACER '+'
  1677.             if(namelen!=0 && (*(up-1)==REPLACER||*(up-1)=='_' ) )
  1678.                 ;        /* suppress it ! */
  1679.             else
  1680.                 if(!trunc_14 || namelen<14) *up++ = REPLACER;
  1681.             }
  1682.         else{
  1683.             if(c=='/') c=':';
  1684.             if(!trunc_14 || namelen<14) *up++ = c;
  1685.             }
  1686.         namelen++;
  1687.         }
  1688.     if (!*cp++) break;
  1689.     *up++ = '/';
  1690.   }
  1691.   if (strlen(uname) >= 100) nametoolong(mname);
  1692. }
  1693.  
  1694. void numstr (p, num, count)
  1695. register char *p;
  1696. register long num;
  1697. register short count;
  1698. {
  1699. /* come fatto da Zacharias lasciava un sacco di '0' in testa, l'unico modo 
  1700. per non farlo è scrivere in un buffer e poi copiare
  1701. -- I (G. Speranza) don't like how Zacharias did it, he wrote directly to
  1702. the destination filling extra space at the beginning with '0's !  It's
  1703. also a risk for compatibility, since the UNIX tar and bar don't write 
  1704. things in that way.
  1705. */
  1706. char buffer[14];
  1707.   buffer[--count] = '\0';
  1708.   if (count != 11) buffer[--count] = ' ';
  1709.   if(count!=0){
  1710.       do{
  1711.         buffer[--count] = '0' + ((short)num & 7);
  1712.         num >>= 3;
  1713.         }
  1714.       while (count && num);
  1715.     }
  1716. strcpy(p,&buffer[count]);
  1717. }
  1718.  
  1719. void statf (fname)
  1720.   char *fname;
  1721. {
  1722.   char name[256];
  1723.   statb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  1724.   statb.ioFVersNum = 0;
  1725.   statb.ioVRefNum = curr_vrefnum;
  1726.   statb.ioFDirIndex = 0;
  1727.   statb.ioDirID = 0;
  1728.   if (PBGetCatInfoSync(&statb) || statb.ioResult) pbsyserr(&statb);
  1729.   statb.ioNamePtr = NULL;
  1730. }
  1731.  
  1732. short getvrefnum (fname)
  1733.   char *fname;
  1734. {
  1735. /* ho il sospetto che non serva più, se serve solo a sapere il vrefnum attuale...
  1736. no, a volte curr_vrefnum è 0, forse serve, e comunque sono poche istruzioni
  1737. */
  1738.   HVolumeParam hpb;
  1739.   char name[256];
  1740.   hpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  1741.   hpb.ioVRefNum = 0;
  1742.   hpb.ioVolIndex = 0;
  1743.   if (PBHGetVInfoSync(&hpb) || hpb.ioResult) pbsyserr(&hpb);
  1744.   return hpb.ioVRefNum;
  1745. }
  1746.  
  1747. void nametoolong (name)
  1748.   char *name;
  1749. {
  1750.   printf("name too long \"%s\"\n", name);
  1751.   raise_error();
  1752. }
  1753.